<?php
// +----------------------------
// | Created by PhpStorm
// +----------------------------
// | Author: YnnSon
// +----------------------------
namespace app\api\service;

use app\lib\exception\CovidException;
use think\Config;
use Yurun\Util\HttpRequest;

class Covid
{
    /**
     * @Desc 获取全国疫情信息
     * @return array
     */
    public static function getChinaData()
    {
        $file = ROOT_PATH . 'public' . DS . 'static' . DS . 'api' . DS . 'covid' . DS . 'china' . DS . date('Ymd') . '.json';
        $config = Config::get('covid');
        // 文件不存在
        if (!file_exists($file)) {
            // 从接口获取数据并保存到文件
            if (self::getAndSaveCovidData($file, $config['china_url'])) {
                // 成功后重新获取
                self::getChinaData();
            } else {
                // 获取失败后读取前一天数据
                $file = ROOT_PATH . 'public' . DS . 'static' . DS . 'api' . DS . 'covid' . DS . 'china' . DS . date('Ymd', strtotime('-1 day')) . '.json';
                // 文件不存在抛出异常
                if (!file_exists($file)) {
                    throw new CovidException([
                        'code'    => 400,
                        'message' => '暂未获取到全国数据',
                    ]);
                }
            }
            // 文件存在但大小不对
        } elseif (10 > filesize($file)) {
            // 删除文件重新获取
            unlink($file);
            self::getChinaData();
        }
        $json_string = file_get_contents($file);
        $result = json_decode($json_string, true);
        if (!is_array($result)) {
            throw new CovidException([
                'code'    => 400,
                'message' => '暂未获取到全国数据',
            ]);
        }
        $chinaData = $result[0];
        return [
            'currentConfirmedCount' => $chinaData['currentConfirmedCount'], // 现有确诊人数
            'currentConfirmedIncr'  => $chinaData['currentConfirmedIncr'] >= 0 ? '+' . $chinaData['currentConfirmedIncr'] : $chinaData['currentConfirmedIncr'], // 现有确诊人数 - 较上日
            'confirmedCount'        => $chinaData['confirmedCount'], // 累计确诊人数
            'confirmedIncr'         => $chinaData['confirmedIncr'] >= 0 ? '+' . $chinaData['confirmedIncr'] : $chinaData['confirmedIncr'], // 累计确诊人数 - 较上日
            'suspectedCount'        => $chinaData['suspectedCount'], // 疑似感染人数
            'suspectedIncr'         => $chinaData['suspectedIncr'] >= 0 ? '+' . $chinaData['suspectedIncr'] : $chinaData['suspectedIncr'], // 疑似感染人数 - 较上日
            'curedCount'            => $chinaData['curedCount'], // 累计治愈人数
            'curedIncr'             => $chinaData['curedIncr'] >= 0 ? '+' . $chinaData['curedIncr'] : $chinaData['curedIncr'], // 累计治愈人数 - 较上日
            'deadCount'             => $chinaData['deadCount'], // 累计死亡人数
            'deadIncr'              => $chinaData['deadIncr'] >= 0 ? '+' . $chinaData['deadIncr'] : $chinaData['deadIncr'], // 累计死亡人数 - 较上日
        ];
    }

    /**
     * @Desc 获取省市疫情信息
     *
     * @param $param
     *
     * @return array
     */
    public static function getAreaData($param)
    {
        // 今天数据
        $now = self::getNowAreaData($param);
        // 昨天数据
        $yesterday = self::getYesterdayAreaData($param);
        $currentConfirmedIncr = $now['currentConfirmedCount'] - $yesterday['currentConfirmedCount'];
        $confirmedIncr = $now['confirmedCount'] - $yesterday['confirmedCount'];
        $suspectedIncr = $now['suspectedCount'] - $yesterday['suspectedCount'];
        $curedIncr = $now['curedCount'] - $yesterday['curedCount'];
        $deadIncr = $now['deadCount'] - $yesterday['deadCount'];
        return [
            'currentConfirmedCount' => $now['currentConfirmedCount'], // 现有确诊人数
            'currentConfirmedIncr'  => $currentConfirmedIncr >= 0 ? '+' . $currentConfirmedIncr : $currentConfirmedIncr, // 现有确诊人数 - 较上日
            'confirmedCount'        => $now['confirmedCount'], // 累计确诊人数
            'confirmedIncr'         => $confirmedIncr >= 0 ? '+' . $confirmedIncr : $confirmedIncr, // 累计确诊人数 - 较上日
            'suspectedCount'        => $now['suspectedCount'], // 疑似感染人数
            'suspectedIncr'         => $suspectedIncr >= 0 ? '+' . $suspectedIncr : $suspectedIncr, // 疑似感染人数 - 较上日
            'curedCount'            => $now['curedCount'], // 累计治愈人数
            'curedIncr'             => $curedIncr >= 0 ? '+' . $curedIncr : $curedIncr, // 累计治愈人数 - 较上日
            'deadCount'             => $now['deadCount'], // 累计死亡人数
            'deadIncr'              => $deadIncr >= 0 ? '+' . $deadIncr : $deadIncr, // 累计死亡人数 - 较上日
        ];
    }

    /**
     * @Desc 获取今天省市疫情信息
     *
     * @param $param
     *
     * @return array|mixed
     */
    public static function getNowAreaData($param)
    {
        $file = ROOT_PATH . 'public' . DS . 'static' . DS . 'api' . DS . 'covid' . DS . 'area' . DS . date('Ymd') . '.json';
        return self::getAreaDataFromFile($file, $param);
    }

    /**
     * @Desc 获取今天省市疫情信息
     *
     * @param $param
     *
     * @return array|mixed
     */
    public static function getYesterdayAreaData($param)
    {
        $file = ROOT_PATH . 'public' . DS . 'static' . DS . 'api' . DS . 'covid' . DS . 'area' . DS . date('Ymd', strtotime('-1 day')) . '.json';
        return self::getAreaDataFromFile($file, $param);
    }

    /**
     * @Desc 从文件中获取省市疫情数据
     *
     * @param $file
     * @param $param
     *
     * @return array
     */
    public static function getAreaDataFromFile($file, $param)
    {
        $config = Config::get('covid');
        // 文件不存在
        if (!file_exists($file)) {
            // 从接口获取数据并保存到文件
            if (self::getAndSaveCovidData($file, $config['area_all_url'])) {
                // 成功后重新获取
                self::getAreaDataFromFile($file, $param);
            } else {
                // 获取失败后读取前一天数据
                $file = ROOT_PATH . 'public' . DS . 'static' . DS . 'api' . DS . 'covid' . DS . 'area' . DS . date('Ymd', strtotime('-1 day')) . '.json';
                // 文件不存在抛出异常
                if (!file_exists($file)) {
                    throw new CovidException([
                        'code'    => 400,
                        'message' => '暂未获取到城市数据',
                    ]);
                }
            }
            // 文件存在但大小不对
        } elseif (10 > filesize($file)) {
            // 删除文件重新获取
            unlink($file);
            self::getAreaDataFromFile($file, $param);
        }
        $json_string = file_get_contents($file);
        $result = json_decode($json_string, true);
        if (!is_array($result)) {
            throw new CovidException([
                'code'    => 400,
                'message' => '暂未获取到城市数据',
            ]);
        }
        $provinceData = $cityData = [];
        foreach ($result as $key => $value) {
            if ($value['provinceName'] == $param['province']) {
                $provinceData = $value['cities'];
            }
        }
        preg_match('/(北京市|天津市|重庆市|上海市)/u', $param['city'], $matchs);
        if (0 < count($matchs)) {
            $cityName = $param['district'];
        } else {
            $cityName = str_replace('市', '', $param['city']);
        }
        foreach ($provinceData as $key => $value) {
            if ($value['cityName'] == $cityName) {
                $cityData = $value;
            }
        }
        return $cityData;
    }

    /**
     * @Desc 获取并保存疫情数据
     *
     * @param string $file  文件路径
     * @param string $url   接口地址
     * @param int    $count 第几次重试
     *
     * @return bool
     */
    public static function getAndSaveCovidData($file, $url, $count = 1)
    {
        // 失败三次
        if (3 <= $count) {
            return false;
        }
        $http = new HttpRequest();
        $response = $http->get($url)->json(true);
        if (!$response['success']) {
            $count++;
            self::getAndSaveCovidData($file, $url, $count);
        }
        $response = json_encode($response['results'], JSON_UNESCAPED_UNICODE);
        // 文件大小不对重新获取
        if (10 > strlen($response)) {
            $count++;
            self::getAndSaveCovidData($file, $url, $count);
        }
        // 写入文件
        file_put_contents($file, $response);
        return true;
    }
}